/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.ui.cd;

import java.awt.CardLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;
import org.bushe.swing.event.EventBus;
import org.bushe.swing.event.annotation.AnnotationProcessor;
import org.bushe.swing.event.annotation.EventSubscriber;

import who.tmap.bo.ThematicMap;
import who.tmap.bo.cd.CDColorPattern;
import who.tmap.bo.cd.CDProportionalSymbols;
import who.tmap.bo.cd.CDTypes;
import who.tmap.bo.cd.CartographicDisplay;
import who.tmap.bo.cd.ColorPatternClassification;
import who.tmap.bo.cd.point.CDPoint;
import who.tmap.bo.cd.point.CDPointDataDrivenSymbol;
import who.tmap.common.TMapException;
import who.tmap.toolkit.MappingToolKit;
import who.tmap.toolkit.impl.CartographicDisplayHelper;
import who.tmap.toolkit.shape.MapShape;
import who.tmap.ui.UserMouseInputListener;
import who.tmap.ui.cd.point.JPanelCDPoint;
import who.tmap.ui.cd.point.JPanelCDPointDataDrivenSymbol;
import who.tmap.ui.event.ColorPatternCDSelected;
import who.tmap.ui.event.DataStructureHasChanged;
import who.tmap.ui.event.OtherCDSelected;
import who.tmap.ui.event.PointCDSelected;
import who.tmap.ui.event.ProportionalSymbolsCDSelected;
import who.tmap.ui.util.MiscUIHelper;
import who.tmap.util.MiscHelper;

/**
 * Manages all the cd panels using a card layout
 * @author stl
 */
public class JFrameCartographicDisplay extends JInternalFrame 
									   implements ComponentListener {//, SimpleObserver, SimpleObserved {

	/*public static final String COLORPATTERN_CD_SELECTED_MSG ="colorPatternCDSelectedMsg_";
	public static final String NB_RANGES_UPDATED_MSG ="nbRangesUpdated_";
	public static final String OTHER_CD_SELECTED_MSG ="othercCDSelectedMsg";  
	public static final String POINT_CD_SELECTED_MSG ="pointCDSelectedMsg";
	public static final String PROPORTIONAL_SYMBOLS_CD_SELECTED_MSG ="proportionalSymbolsCDSelected";*/
	
    private static Logger logger = Logger.getLogger(JFrameCartographicDisplay.class);   	
	
    private JInternalFrame thisFrame =this;
    
	private ThematicMap thematicMap =null;
	
	private boolean dirtyFlag =false;
	private boolean wizardMode =false;
	private MappingToolKit mtk =null;
	private UserMouseInputListener mil =null;
	private MiscUIHelper miscUIHelper =new MiscUIHelper();
	private PanelCD currentJPanelCD =null;	
	private JPanelCDPoint cdp =null;
	//private SimpleObservedImpl observedImpl =new SimpleObservedImpl();  
	
	private JComboBox jComboBoxCartographicDisplay = null;
	private JButton jButtonApply =null;
	private JPanel jPanel = null;
	private JPanel jPanelInfo = null;
	private JPanel jPanelCombo = null;
	
	public JFrameCartographicDisplay() {
		super();
		
		initialize();
	}	
	
	public JFrameCartographicDisplay( MappingToolKit mtk, UserMouseInputListener mil) {
		super();
		
		this.mtk =mtk;
		this.mil =mil;
		
		initialize();
	}
	
	/**
	 * This method initializes this
	 * 
	 * @return void
	 */
	private void initialize() {
		getContentPane().setLayout(null);
		getContentPane().add(getJComboBoxCartographicDisplay());

		setContentPane(getJPanel());
		setSize(373, 200);
		setTitle( "Cartographic Display" );
		
		getJComboBoxCartographicDisplay().setBounds( 170, 10, 150, 30 );
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setClosable( false );
		
		setFrameIcon( new MiscHelper().getImageIcon("ic_display2.gif") );	
		
		AnnotationProcessor.process(this);
	}
	
	public CartographicDisplay retrieveCartographicDisplay() {
		CartographicDisplay cd =null;
		
		if ( currentJPanelCD != null ) {
			try {
				cd =currentJPanelCD.getCartographicDisplay();
				thematicMap.setCartographicDisplay( cd );				
			} catch (TMapException e) {
				e.printStackTrace();
			}
		}
		
		return cd;
	}
	
	public boolean isPointCDSelected() {
		return currentJPanelCD == cdp;
	}
	
	private JButton getJButtonApply() {
		if ( jButtonApply == null ) {
			jButtonApply =new JButton();
			jButtonApply.setText( "Apply" );
			jButtonApply.setFont(new Font("Dialog", Font.BOLD, 12));
			jButtonApply.addActionListener( new ActionListener() { 
				public void actionPerformed( ActionEvent e) {
					apply();
				}
			});			
		}
		
		return jButtonApply;
	}

	public void apply() {
		if ( currentJPanelCD != null ) {
			
			CartographicDisplay cd =null;
			try {
				cd =currentJPanelCD.getCartographicDisplay();
				
				thematicMap.setCartographicDisplay( cd );
							
				if ( cd instanceof CDColorPattern && ((JPanelCDColorPattern)currentJPanelCD).isRangesUpdated() ) {
					/*if ( ((CDColorPattern)cd).getClassification() == ColorPatternClassification.NON_NUMERIC )  {
						((JPanelCDColorPattern)currentJPanelCD).processNonNumeric();
					} else {*/
					((JPanelCDColorPattern)currentJPanelCD).updateRanges();
					((JPanelCDColorPattern)currentJPanelCD).refreshRanges();
					//}
				}
			        				
				Map<MapShape, Object> data =new CartographicDisplayHelper()
													.assignValues( mtk, thematicMap.getData(), cd );
				cd.setPolygonAssociatedData( data );
				mtk.setCartographicDisplayVisible( true );
				
				mtk.repaint();					
				
				// To refresh color/pattern ranges
				if ( cd instanceof CDColorPattern 
						&& ((CDColorPattern)cd).getClassification() != ColorPatternClassification.USER_DEFINED_RANGES ) {		
			        SwingUtilities.invokeLater( new Runnable() {
			            public void run() {
			            	((JPanelCDColorPattern)currentJPanelCD).refreshRanges();
			            }
			        });
				}							
				
				if ( cd instanceof CDPointDataDrivenSymbol ) {
					JPanelCDPoint panelCDPoint =(JPanelCDPoint)currentJPanelCD;
					((JPanelCDPointDataDrivenSymbol)panelCDPoint.getCurrentPanel()).refreshTable();
				}
				
			
			} catch (TMapException e1) {
				miscUIHelper.displayErrorMessage( thisFrame, e1 );
			}
				
		} else {
			miscUIHelper.displayErrorMessage( thisFrame, "Cannot find current selected panel" );
		}
	}
	
	/**
	 * This method initializes jComboBoxCartographicDisplay
	 * 
	 * @return javax.swing.JComboBox
	 */
	public JComboBox getJComboBoxCartographicDisplay() {
		if(jComboBoxCartographicDisplay == null) {
			jComboBoxCartographicDisplay = new JComboBox( CDTypes.names );
			jComboBoxCartographicDisplay.setFont(new Font("Dialog", Font.PLAIN, 12));

			jComboBoxCartographicDisplay.addItemListener(new ItemListener() { 
				public void itemStateChanged(ItemEvent e) {
					if ( e.getStateChange() == ItemEvent.SELECTED ) {
						CardLayout cl = (CardLayout)(getJPanelInfo().getLayout());
					
						cl.show( getJPanelInfo(), (String)e.getItem() );
					}

				}
			});	
			
		}
		return jComboBoxCartographicDisplay;
	}
	
	public void setWizardMode(boolean b) {
		wizardMode = b;
		
		setResizable( !wizardMode );
		setMaximizable( !wizardMode );
		setIconifiable( !wizardMode );
		
		if ( wizardMode ) {	
			setTitle( "Thematic Map Wizard - " + getTitle() );
		}
	}	
	
	/**
	 * This method initializes jPanel
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanel() {
		if(jPanel == null) {
			jPanel = new JPanel();
			jPanel.setLayout(new BoxLayout(jPanel, BoxLayout.Y_AXIS));
			jPanel.add(getJPanelCombo(), null);			
			jPanel.add(getJPanelInfo(), null);
		}
		return jPanel;
	}
	
	/**
	 * This method initializes jPanelInfo
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelInfo() {
		if(jPanelInfo == null) {
			jPanelInfo = new JPanel();
			jPanelInfo.setLayout(new java.awt.CardLayout());		
			
			JPanelCDColorPattern cdc =new JPanelCDColorPattern();
			cdc.addComponentListener( this );
			jPanelInfo.add( cdc, CDTypes.names[ CDTypes.COLOR_PATTERN ] );
			//cdc.registerObserver( (SimpleObserver)thisFrame );
			
			JPanelCDProportionalSymbols cdps =new JPanelCDProportionalSymbols();
			cdps.addComponentListener( this );
			jPanelInfo.add( cdps, CDTypes.names[ CDTypes.PROPORTIONAL_SYMBOLS ] );
			
			JPanelCDDotDensity cddd =new JPanelCDDotDensity();
			cddd.addComponentListener( this );
			jPanelInfo.add( cddd, CDTypes.names[ CDTypes.DOT_DENSITY ] );
			
			cdp =new JPanelCDPoint();
			cdp.addComponentListener( this );
			jPanelInfo.add( cdp, CDTypes.names[ CDTypes.POINT ] );				
			
			currentJPanelCD =cdc;
		
			jPanelInfo.setBorder( BorderFactory.createEmptyBorder(5,5,5,5) );
		}
		return jPanelInfo;
	}
	
	/**
	 * This method initializes jPanelCombo
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelCombo() {
		if(jPanelCombo == null) {
			jPanelCombo = new JPanel();
			FlowLayout flowLayout =new FlowLayout();
			flowLayout.setAlignment(java.awt.FlowLayout.RIGHT);
			jPanelCombo.setLayout( flowLayout );

			jPanelCombo.setName("jPanelCombo");
			jPanelCombo.add(getJComboBoxCartographicDisplay());
			jPanelCombo.add(getJButtonApply());
		}
		return jPanelCombo;
	}
	
	public ThematicMap getThematicMap() {
		return thematicMap;
	}
	
	public void setThematicMap(ThematicMap thematicMap) {
		this.thematicMap = thematicMap;
	}
	
	public void componentHidden(ComponentEvent e) {}
	
	public void componentMoved(ComponentEvent e) {}
	
	public void componentResized(ComponentEvent e) {}
	
	/**
	 * Show a panel of the card layout
	 */
	public void componentShown(ComponentEvent e) {
		showComponent((PanelCD)e.getComponent());
	}	
	
	private void showComponent( PanelCD jPanelCD ) {
		
		String joinIdColumnName =currentJPanelCD.getJoinIdColumnName();
		String dataColumnName =currentJPanelCD.getDataColumnName();
		
		logger.debug( "joinIdColumnName=[" + joinIdColumnName + "], dataColumnName=[" + dataColumnName + "]" );
		
		currentJPanelCD =jPanelCD;
		currentJPanelCD.setThematicMap( thematicMap );
		currentJPanelCD.refreshAttrColumnNames();
		
		if ( joinIdColumnName != null ) {
			currentJPanelCD.setJoinIdColumnName( joinIdColumnName );
		}
		
		if ( dataColumnName != null ) {
			currentJPanelCD.setDataColumnName( dataColumnName );
		}		
		
		currentJPanelCD.refreshData();	
		
		CartographicDisplay cd =null;

		try {
			cd =currentJPanelCD.getCartographicDisplay();
		} catch( Exception e2 ) {
			logger.error( e2 );
		}
		
		String msg;
		if ( cd instanceof CDColorPattern ) {
			//msg =COLORPATTERN_CD_SELECTED_MSG + ((CDColorPattern)cd).getRanges().size() + "_" + ((CDColorPattern)cd).getClassification();
			
			EventBus.publish( new ColorPatternCDSelected( ((CDColorPattern)cd).getRanges().size(), 
														 ((CDColorPattern)cd).getClassification() ) );
		} else if ( cd instanceof CDProportionalSymbols ) {
			//msg =PROPORTIONAL_SYMBOLS_CD_SELECTED_MSG;
			
			EventBus.publish( new ProportionalSymbolsCDSelected() );
		} else if ( cd instanceof CDPoint ) {
			//msg =POINT_CD_SELECTED_MSG;
			
			EventBus.publish( new PointCDSelected() );
		} else {
			//msg =OTHER_CD_SELECTED_MSG;
			
			EventBus.publish( new OtherCDSelected() );
		}
		
		//notifyObservers( msg );	
		
		setDirty( dirtyFlag );
		
		dirtyFlag =true;
	}
	
	public void setMappingToolKit( MappingToolKit mtk ) {
		this.mtk =mtk;
	}		
	
	public void setMil( UserMouseInputListener mil ) {
		this.mil =mil;
	}
	
	public void refreshData() {
		CartographicDisplay cd =thematicMap.getCartographicDisplay();

		int type;
		if ( cd != null ) {
			type =cd.getType();
		} else {
			type =CDTypes.DEFAULT_CD;
		}
		
		// because of swing threading issues, the dirty flag is set as a class variable...
		dirtyFlag =false;		
		
		// special case for cd point
		if ( type >= CDTypes.POINT_BASIC && type <= CDTypes.POINT_DATA_DRIVEN_SYMBOL_AND_SIZE ) {
			type =CDTypes.POINT;
		}
		
		if ( type == jComboBoxCartographicDisplay.getSelectedIndex() ) {
			showComponent( (PanelCD)jPanelInfo.getComponent(type) );
		} else {
			jComboBoxCartographicDisplay.setSelectedIndex( type );		
		}

		// refresh data is performed by the componentShown method
		// because of Swing threading issues
	}
	
	public CartographicDisplay getCartographicDisplay() throws TMapException {
		return currentJPanelCD.getCartographicDisplay();
	}
	
	public JPanelCDPoint getJPanelCDPoint() {
		return cdp;
	}
	
	public String getXColumn() {
		return (String)cdp.getJComboBoxXColumn().getSelectedItem();
	}
	
	public String getYColumn() {
		return (String)cdp.getJComboBoxYColumn().getSelectedItem();
	}	

	/*public void sendNotify(Object msg) {
		logger.debug( "Notification received " + msg );
		//if ( msg instanceof List) {
		//	currentJPanelCD.refreshAttrColumnNames();
		//} else 
		if ( msg instanceof String ) {
			notifyObservers( msg );
		}
	}*/
	
	public void enableWizardMode( boolean enabled ) {
		setIconifiable( !enabled );
		setMaximizable( !enabled );		
	}
	
	public boolean isDirty() {
		return currentJPanelCD.isDirty();
	}
	
	public void setDirty( boolean dirty ) {
		if ( currentJPanelCD != null ) {
			currentJPanelCD.setDirty( dirty );
		}
	}

	/*public void registerObserver(SimpleObserver observer) {
		observedImpl.registerObserver( observer );
	}

	public void unregisterObserver(SimpleObserver observer) {
		observedImpl.unregisterObserver( observer );
	}
	
	public void notifyObservers( Object msg ) {
		observedImpl.notifyObservers( msg );
	}*/
	
	@EventSubscriber(eventClass=DataStructureHasChanged.class)
    public void onEvent(DataStructureHasChanged event) {
		logger.debug( "Notification received: " + event.getClass().getName() );
		
		currentJPanelCD.refreshAttrColumnNames();
    }
	
	public void applyPointEntryStructure() {
		cdp.applyEntryPointStructure();
	}
	
}  
